﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using ActivePalInterop;
using ActivePalInterop.Data;
using Microsoft.Win32;
using ActivePalInterop.Events;
using System.ComponentModel;
using System.Windows.Threading;
using System.Threading;
using ActivePal.Properties;
using System.Collections;

namespace ActivePal
{
    /// <summary>
    /// Interaction logic for Main.xaml
    /// </summary>
    public partial class Main : Window
    {
        #region Fields

        /// <summary>
        /// Use this object for long lasting non GUI operations for reading files
        /// </summary>        
        private Uploader currentUploader;

        #endregion

        #region Properties

        /// <summary>
        /// The name of a file to be uploaded into the database
        /// </summary>
        public string UploadFileName { get; set; }

        /// <summary>
        /// Count of rows to be skipped while reading headered file
        /// </summary>
        public int SkippedHeaderCount { get; set; }


        /// <summary>
        /// Gets or sets a session name for uploading into a database
        /// </summary>
        public string SessionName { get; set; }

        /// <summary>
        /// Gets or sets uploader instance independently of the caller thread
        /// </summary>
        public Uploader CurrentUploader
        {
            get
            {
                Uploader tmp = null;
                //need for async calls 
                Dispatcher.Invoke(DispatcherPriority.Send,
                    (ThreadStart)delegate
                    {
                        tmp = currentUploader;
                    });

                return tmp;
            }
            set
            {
                //need for async calls 
                Dispatcher.Invoke(DispatcherPriority.Send,
                    (ThreadStart)delegate
                    {
                        currentUploader = value;
                    });
            }
        }

        /// <summary>
        /// Gets string from a session comment control
        /// </summary>
        public string SessionComments
        {
            get
            {
                string tmp = String.Empty;
                //need for async calls 
                Dispatcher.Invoke(DispatcherPriority.Send,
                    (ThreadStart)delegate
                    {
                            TextRange textRange = new TextRange(rtbSessionComments.Document.ContentStart, rtbSessionComments.Document.ContentEnd);
                            tmp = textRange.Text.Trim();
                    });

                return tmp;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Creates a new main window
        /// </summary>
        public Main()
        {
            InitializeComponent();
            Initialize();
        }

        #endregion

        #region Main window events

        /// <summary>
        /// Handles debug messages event
        /// </summary>        
        private void Main_DebugMessage(MessageEventArgs args)
        {
            OutputDebugMessage(args.Message);
        }
                
        /// <summary>
        /// Handles update view event, in case database or other data had been updated
        /// </summary>        
        private void Main_TriggerViewUpdate(object sender, EventArgs e)
        {
            PeopleViewCtrl.UpdateViewFromItemSource();
        }

        /// <summary>
        /// Initialize, subscribe to events and run the worker thread
        /// </summary>        
        private void btnUpload_Click(object sender, RoutedEventArgs e)
        {
            titledProgressBar.ClearToDefault();
            workerReader.RunWorkerAsync(txtFilePath.Text);
        }

        /// <summary>
        /// Opens a file open dialog, if OK pressed saves the path to a textbox
        /// </summary>
        private void btnBrowse_Click(object sender, RoutedEventArgs e)
        {
            // create and show an open file dialog
            OpenFileDialog dlgOpen = new OpenFileDialog();
            bool OKPressed = dlgOpen.ShowDialog() ?? false;

            if (OKPressed)
            {
                txtFilePath.Text = dlgOpen.FileName;
                btnUpload.IsEnabled = true;
            }
        }

        /// <summary>
        /// Stops any worker if running
        /// </summary>        
        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            if (workerReader.IsBusy)
            {
                workerReader.CancelAsync();
            }
            if (workerBulkUploader.IsBusy)
            {
                workerBulkUploader.CancelAsync();
            }
        }

        /// <summary>
        /// Saves settings to default storage
        /// </summary>        
        private void btnSaveSattings_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Settings.Default.Save();
                Settings.Default.Upgrade();
                OutputDebugMessage("Settigns saved.");
                tblockSaveResult.Text = TestResultText.FunSuccedded;
            }
            catch (Exception ex)
            {
                OutputDebugMessage("Failed to save settings. " + ex.Message);
                tblockSaveResult.Text = TestResultText.FunFailed;
            }

        }

        /// <summary>
        /// Grabs connection string from a text bow and checks if connection could be opened
        /// </summary>        
        private void btnTestConnection_Click(object sender, RoutedEventArgs e)
        {
            string msg = DbFacade.GetInstance().TestConnection(tbConnectionString.Text);
            if (msg == String.Empty)
            {
                tblockTestResult.Text = TestResultText.FunSuccedded;
            }
            else
            {
                tblockTestResult.Text = TestResultText.FunFailed;
                MessageBox.Show(msg);
            }
        }

        /// <summary>
        /// Checks for Setting tabs to be selected and adjust controls' state
        /// </summary>        
        private void tabControl1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.Source is TabControl)
            {
                TabControl c = e.Source as TabControl;
                if (c.SelectedItem is TabItem)
                {
                    TabItem i = c.SelectedItem as TabItem;
                    if (i.Header.ToString() != "Settings")
                    {
                        tblockSaveResult.Text = String.Empty;
                        tblockTestResult.Text = String.Empty;
                    }
                }
            }
        }

        /// <summary>
        /// Buttin Add click handler
        /// </summary>        
        private void btAddPerson_Click(object sender, RoutedEventArgs e)
        {
            AddPerson();
        }

        /// <summary>
        /// Buttin Edit click handler
        /// </summary>        
        private void btEditPerson_Click(object sender, RoutedEventArgs e)
        {
            EditPerson();
        }

        /// <summary>
        /// Buttin Delete click handler
        /// </summary>        
        private void btDeletePerson_Click(object sender, RoutedEventArgs e)
        {
            DeletePerson();
        }

        #endregion

        /// <summary>
        /// Append text and new line chars to the output textbox independently of the caller thread
        /// </summary>
        /// <param name="msg">message to be appended</param>
        public void OutputDebugMessage(string msg)
        {
            //need for async calls to GUI
            Dispatcher.Invoke(DispatcherPriority.Send,
                (ThreadStart)delegate
                {
                    rtbOutput.AppendText(Environment.NewLine + msg);
                });
        }

        /// <summary>
        /// Update GUI acordingly to the work status
        /// </summary>
        private void UpdateGUIWorkStarted()
        {
            Dispatcher.Invoke(DispatcherPriority.Send,
                (ThreadStart)delegate
                {
                    btnUpload.IsEnabled = false;
                    btnBrowse.IsEnabled = false;
                    btnCancel.IsEnabled = true;
                });
        }

        /// <summary>
        /// Update GUI acordingly to the work status
        /// </summary>
        private void UpdateGUIWorkStopped()
        {
            Dispatcher.Invoke(DispatcherPriority.Send,
                (ThreadStart)delegate
                {
                    btnUpload.IsEnabled = true;
                    btnBrowse.IsEnabled = true;
                    btnCancel.IsEnabled = false;
                });
        }

        /// <summary>
        /// Init inner controls
        /// </summary>
        private void Initialize()
        {
            //set up initial settings from settings
            DbFacade.GetInstance().ConnString = Settings.Default.SqlConn;

            //workerReader
            workerReader = new BackgroundWorker();
            workerReader.DoWork += new DoWorkEventHandler(workerReader_DoWork);
            workerReader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerReader_Completed);
            workerReader.ProgressChanged += new ProgressChangedEventHandler(workerReader_ProgressChanged);
            workerReader.WorkerReportsProgress = true;
            workerReader.WorkerSupportsCancellation = true;

            //workerBulkUploader            
            workerBulkUploader = new BackgroundWorker();
            workerBulkUploader.DoWork += new DoWorkEventHandler(workerBulkUploader_DoWork);
            workerBulkUploader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerBulkUploader_Completed);
            workerBulkUploader.ProgressChanged += new ProgressChangedEventHandler(workerBulkUploader_ProgressChanged);
            workerBulkUploader.WorkerReportsProgress = true;
            workerBulkUploader.WorkerSupportsCancellation = true;

            //CurrentUploader = new Uploader(String.Empty, 0, null); //to be initialized in a main thread
            DbFacade.GetInstance().DebugMessage += new StaticMessageEventHandler(Main_DebugMessage);
            DbFacade.GetInstance().TestConnection();

            PeopleViewCtrl.UpdateViewFromItemSource();

            Paragraph p = rtbOutput.Document.Blocks.FirstBlock as Paragraph;
            p.Margin = new Thickness(0);
            p.Padding = new Thickness(0);
            p.LineHeight = 1;

        }       

        /// <summary>
        /// Opens a new window to allow user create a new person
        /// </summary>
        private void AddPerson()
        {
            PersonalDataWindow windowPerson = new PersonalDataWindow();
            windowPerson.DebugMessage += Main_DebugMessage;
            windowPerson.TriggerViewUpdate += Main_TriggerViewUpdate;
            windowPerson.Owner = this;
            windowPerson.Show();            
        }

        private void EditPerson()
        {
            try
            {
                Person p = (Person)PeopleViewCtrl.SelectedItems[0];
                PersonalDataWindow windowPerson = new PersonalDataWindow(p, WindowMode.Edit);
                windowPerson.DebugMessage += Main_DebugMessage;
                windowPerson.TriggerViewUpdate += Main_TriggerViewUpdate;
                windowPerson.Owner = this;
                windowPerson.Show();            
            }
            catch (Exception ex)
            {
                OutputDebugMessage("Failed to edit person: " + ex.Message);
            }
        }

        private void DeletePerson()
        {
            try
            {
                IList people = (IList)PeopleViewCtrl.SelectedItems;
                string successMsg = "Record{0} deleted.";
                int i = 0;
                foreach (Person p in people)
                {
                    bool res = p.Delete();
                    if (res)
                    {                        
                        Main_TriggerViewUpdate(this, null);
                    }
                    else
                    {
                        OutputDebugMessage("Failed to delete the record.");
                    }
                    i++;
                }
                string msg = i > 1 ?
                    String.Format(successMsg, "s")
                    :
                    String.Format(successMsg, String.Empty);

                OutputDebugMessage(msg);
            }
            catch (Exception ex)
            {
                OutputDebugMessage("Failed to edit person: " + ex.Message);
            }
        }

        private void PeopleViewCtrl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            EditPerson();
        }
    }
}
